package com.sdk;


import android.app.Activity;
import android.app.Service;
import android.content.ComponentName;
import android.content.Context;
import android.content.Intent;
import android.content.SharedPreferences;
import android.media.AudioManager;
import android.media.MediaPlayer;
import android.os.Bundle;
import android.os.Environment;
import android.os.Handler;
import android.os.IBinder;
import android.os.Message;
import android.text.TextUtils;
import android.view.View;
import android.view.Window;
import android.view.WindowManager;
import android.widget.Toast;

import com.com.unionpay.constant.Config;
import com.com.unionpay.constant.Constant;
import com.com.unionpay.speech.receiver.BluetoothReceiver;
import com.com.unionpay.speech.util.FileUtil;
import com.com.unionpay.utils.HttpUtil;
import com.com.unionpay.utils.JsonParser;
import com.iflytek.cloud.ErrorCode;
import com.iflytek.cloud.InitListener;
import com.iflytek.cloud.RecognizerListener;
import com.iflytek.cloud.RecognizerResult;
import com.iflytek.cloud.RequestListener;
import com.iflytek.cloud.SpeechConstant;
import com.iflytek.cloud.SpeechError;
import com.iflytek.cloud.SpeechRecognizer;
import com.iflytek.cloud.VoiceWakeuper;
import com.iflytek.cloud.WakeuperListener;
import com.iflytek.cloud.WakeuperResult;
import com.iflytek.cloud.ui.RecognizerDialog;
import com.iflytek.cloud.util.ResourceUtil;

import org.greenrobot.eventbus.EventBus;
import org.greenrobot.eventbus.Subscribe;
import org.greenrobot.eventbus.ThreadMode;
import org.json.JSONException;
import org.json.JSONObject;
import org.json.JSONTokener;

import java.io.BufferedWriter;
import java.io.IOException;
import java.util.HashMap;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;

import payment.mobilepos.unionpay.com.R;

import static com.com.unionpay.constant.Constant.transData;


public class SpeechDealService extends Service {
    //唤醒成功识别码
    int STATUS_WAKEUP_SUCCESS = 7001;
    int STATUS_WAKEUP_EXIT = 7003;

    //语音识别结果会多次回调，设置时间过滤
    private int backTrackInMs = 1500;
    private long lastTime = 0;

    private final static int MAX = 3000;
    private final static int MIN = 0;
    private int curThresh = 1450;
    private String threshStr = "门限值：";
    private String keep_alive = "1";//0为只唤醒一次，1表示循环唤醒
    private String ivwNetMode = "2";//0为关闭闭环优化，1,2有开启闭环优化，

    private boolean allowBLT = false;
    private boolean allowWakeUp = false;
    private boolean allowMQTT = false;

    private AppManager mAppManager;
    private MediaPlayer mediaPlayer;
    private AudioManager mAudioManager;
    private MQTTService mqttService;
    private Map<String, Object> mParams;
    // 用HashMap存储听写结果
    private HashMap<String, String> mRecognizerResults = new LinkedHashMap<String, String>();
    private ComponentName mEventReceiver;
    private String mSamplePath;
    private List<String> mMessage;
    private BufferedWriter out;
    private SpeechRecognizer mRecognizer;
    private RecognizerDialog mRecognizerDialog;
    private SharedPreferences mSharedPreferences;
    private boolean mTranslateEnable = false;
    private String recognizerResult;
    private String mEngineType = SpeechConstant.TYPE_CLOUD;
    private int ret;
    private VoiceWakeuper mWakeuper;


    @Override
    public void onCreate() {
        super.onCreate();
        mAppManager = AppManager.getInstance();
        LogUtils.e("speechpopdeal启动");
    }

    @Override
    public int onStartCommand(Intent intent, int flags, int startId) {
        if (!EventBus.getDefault().isRegistered(this)) {
            EventBus.getDefault().register(this);
        }

        initRecognizer();

        List<Enum<ActiveMode>> activeMode = mAppManager.getSpeechActiveMode();
        if (activeMode.contains(ActiveMode.BLUETOOTH)) {
            allowBLT = true;
            initBlueTooth();
        }

        if (activeMode.contains(ActiveMode.SPEECH_WAKEUP)) {
            allowWakeUp = true;
            initSpeechWakeUp();
//            queryResource();
        }

        if (activeMode.contains(ActiveMode.MQTT)) {
            allowMQTT = true;
            initMQTT();
        }

        handler.postAtTime(mRunnable, 500);
        //添加添加前后台service的处理
        ActivityLifecycle.getInstance().addListener(new ActivityLifecycle.Listener() {
            @Override
            public void onBecameForeground() {
                //TODO 添加针对不允许启动百度语音的界面的逻辑
                if (mWakeuper != null)
                    mWakeuper.startListening(mWakeuperListener);
                if (mRecognizer != null)
                    mRecognizer.startListening(mRecognizerListener);
            }

            @Override
            public void onBecameBackground() {
                mWakeuper.cancel();
                mRecognizer.cancel();
                mAudioManager.setBluetoothScoOn(false);
                mAudioManager.stopBluetoothSco();
            }


            @Override
            public void onActivityResume(Activity activity) {
                if (mSpeechDialog != null) {
                    if (mSpeechDialog.isShowing()) {
                        mSpeechDialog.hide();
                    }
                    mSpeechDialog = null;
                }
                resetActivityMode(activity);
            }
        });
        return super.onStartCommand(intent, flags, startId);
    }


    /**
     * 当activity onresume的时候获取activity的ActivityMode 对服务进行重置
     *
     * @param activity
     */
    private void resetActivityMode(Activity activity) {
        List<Enum<ActiveMode>> speechActiveMode = mAppManager.getSpeechActiveMode();
        if (speechActiveMode != null && speechActiveMode.size() != 0) {
            allowWakeUp = speechActiveMode.contains(ActiveMode.SPEECH_WAKEUP);
            allowBLT = speechActiveMode.contains(ActiveMode.BLUETOOTH);
            allowMQTT = speechActiveMode.contains(ActiveMode.MQTT);
        } else {
            allowWakeUp = allowBLT = allowMQTT = false;
        }


        mAudioManager.setBluetoothScoOn(false);
        mAudioManager.stopBluetoothSco();

    }


    /**
     * 初始化百度语音
     */
    private void initRecognizer() {
        // 初始化识别无UI识别对象
        // 使用SpeechRecognizer对象，可根据回调消息自定义界面；
        mRecognizer = SpeechRecognizer.createRecognizer(SpeechDealService.this, mInitListener);
        mSharedPreferences = getSharedPreferences(Constant.KEY_SHARED_PREFERENCES_NAME,
                Activity.MODE_PRIVATE);
        String sampleDir = "CUPMobilePos";
        mSamplePath = Environment.getExternalStorageDirectory().toString() + "/" + sampleDir;
        if (!FileUtil.makeDir(mSamplePath)) {
            mSamplePath = getExternalFilesDir(sampleDir).getAbsolutePath();
            if (!FileUtil.makeDir(mSamplePath)) {
                throw new RuntimeException("创建临时目录失败 :" + mSamplePath);
            }
        }
    }

    /**
     * 唤醒功能的唤醒词是“银联银联”
     */
    private void initSpeechWakeUp() {
        mWakeuper = VoiceWakeuper.createWakeuper(this, mInitListener);
        //非空判断，防止因空指针使程序崩溃
        mWakeuper = VoiceWakeuper.getWakeuper();
        if (mWakeuper != null) {
            String resultString = "";

            // 清空参数
            mWakeuper.setParameter(SpeechConstant.PARAMS, null);
            // 唤醒门限值，根据资源携带的唤醒词个数按照“id:门限;id:门限”的格式传入
            mWakeuper.setParameter(SpeechConstant.IVW_THRESHOLD, "0:" + curThresh);
            // 设置唤醒模式
            mWakeuper.setParameter(SpeechConstant.IVW_SST, "wakeup");
            // 设置持续进行唤醒
            mWakeuper.setParameter(SpeechConstant.KEEP_ALIVE, keep_alive);
            // 设置闭环优化网络模式
            mWakeuper.setParameter(SpeechConstant.IVW_NET_MODE, ivwNetMode);
            // 设置唤醒资源路径
            mWakeuper.setParameter(SpeechConstant.IVW_RES_PATH, getResource());
            // 设置唤醒录音保存路径，保存最近一分钟的音频
            mWakeuper.setParameter(SpeechConstant.IVW_AUDIO_PATH, mSamplePath + "/wakeup.wav");
            mWakeuper.setParameter(SpeechConstant.AUDIO_FORMAT, "wav");
            // 如有需要，设置 NOTIFY_RECORD_DATA 以实时通过 onEvent 返回录音音频流字节
            //mIvw.setParameter( SpeechConstant.NOTIFY_RECORD_DATA, "1" );

            // 启动唤醒
            mWakeuper.startListening(mWakeuperListener);
        }
//            ret = mWakeuper.startListening( mWakeuperListener );
    }

    private void initBlueTooth() {
        mAudioManager = (AudioManager) getSystemService(Context.AUDIO_SERVICE);
        mEventReceiver = new ComponentName(
                this,
                BluetoothReceiver.class);
        mAudioManager.registerMediaButtonEventReceiver(mEventReceiver);
        mAudioManager.setBluetoothScoOn(true);
        mAudioManager.startBluetoothSco();

        //播放语音文件
        mediaPlayer = MediaPlayer.create(this, R.raw.lapple);
        try {
            mediaPlayer.setAudioStreamType(AudioManager.STREAM_MUSIC);
            mediaPlayer.prepareAsync();
        } catch (Exception e) {
            e.printStackTrace();
        }

    }

    private void initMQTT() {
        mqttService = new MQTTService(this);
    }


    Runnable mRunnable = new Runnable() {
        @Override
        public void run() {
            if (allowBLT) {
                mediaPlayer.start();
            } else if (allowMQTT) {
                MQTTService.publish(MQTTService.TOPIC_QPOBC_REQUEST, transData);
            }
        }
    };


    Handler handler = new Handler() {
        @Override
        public void handleMessage(Message msg) {
            super.handleMessage(msg);
        }

    };


    /**
     * speechDealService 需要长期在后台运行，而android系统会不定期杀死处于后台的service
     * 无法 优化内存，包括{@link AppManager#getActivityList()}clear 操作
     */
    @Override
    public void onDestroy() {
        EventBus.getDefault().unregister(this);
        Config.IS_SPEECHSERVICE_ALIVE = false;
        mAudioManager.unregisterMediaButtonEventReceiver(mEventReceiver);
        LogUtils.e("SpeechDealService destroy");
        mediaPlayer.release();
        mediaPlayer = null;
        // 关闭蓝牙
        mAudioManager.setBluetoothScoOn(false);
        mAudioManager.stopBluetoothSco();
        mqttService.stopConnect();
        if (null != mRecognizer) {
            // 退出时释放连接
            mRecognizer.cancel();
            mRecognizer.destroy();
        }
        mWakeuper = VoiceWakeuper.getWakeuper();
        if (mWakeuper != null) {
            mWakeuper.destroy();
        }
        super.onDestroy();
    }

    @Override
    public IBinder onBind(Intent intent) {
        return null;
    }

    /**
     * 当收到语音弹框请求时，判断栈顶的Activity是否是可弹框页面
     * <p>
     */
    @Subscribe(threadMode = ThreadMode.MAIN)
    public void onMessageEvent(MessageEvent event) throws IOException {
        if (event.getAction() == Constant.EVENT_ASR_RESULT) {
            //上传语音文件
            if (mMessage != null && mMessage.size() != 0 && !TextUtils.isEmpty(mMessage.get(0))) {
                String uploadUrl = "http://212.64.88.43:8080/speech/upload/uploadFile";
                HttpUtil.upLoadFile(mSamplePath + "/outfile.pcm", mMessage.get(0), uploadUrl);
            }

        } else if (event.getMessage() == ActiveMode.SPEECH_WAKEUP && allowWakeUp) {
            showSpeechDialog();
        } else if (event.getMessage() == ActiveMode.BLUETOOTH && allowBLT) {
            showSpeechDialog();
        } else if (event.getMessage() == ActiveMode.MQTT && allowMQTT) {
            showSpeechDialog();
        } else if (event.getMessage() == ActiveMode.CLICK) {
            showSpeechDialog();
        }

    }

    SpeechDialog mSpeechDialog;

    /**
     * 开启百度语音输入
     */
    private void showSpeechDialog() {
        setParam();

        if (mSpeechDialog != null) {
            if (mSpeechDialog.isShowing()) {
                mSpeechDialog.hide();
            }
            mSpeechDialog = null;
        }
        //-------设置位置
        mSpeechDialog = new SpeechDialog(mAppManager.getCurrentActivity(), R.style.CustomDialog);
        Window win = mSpeechDialog.getWindow();
        win.setFlags(
                WindowManager.LayoutParams.FLAG_ALT_FOCUSABLE_IM,
                WindowManager.LayoutParams.FLAG_ALT_FOCUSABLE_IM);
        WindowManager.LayoutParams params = new WindowManager.LayoutParams();
        params.y = (int) (-100 * getResources().getDisplayMetrics().density);
        win.setAttributes(params);
        mSpeechDialog.setCanceledOnTouchOutside(true);
        mSpeechDialog.setOnDismissListener(dialog -> {
            mSpeechDialog.getWaveView().destroyWaveView();
        });
        mSpeechDialog.show();
//      不显示听写对话框
        ret = mRecognizer.startListening(mRecognizerListener);
        if (ret != ErrorCode.SUCCESS) {
            LogUtils.e("听写失败,错误码：" + ret);
        } else {
            Toast.makeText(this, getString(R.string.text_begin), Toast.LENGTH_SHORT).show();
        }
    }


    // 点击“开始识别”按钮
    private void startWakeUp() {
    }

    private WakeuperListener mWakeuperListener = new WakeuperListener() {
        @Override
        public void onBeginOfSpeech() {
            LogUtils.e("startWakeup");
        }

        @Override
        public void onResult(WakeuperResult wakeuperResult) {
            if (allowWakeUp) {
                showSpeechDialog();
            }
        }

        @Override
        public void onError(SpeechError speechError) {
            LogUtils.e("speechError=" + speechError.getErrorDescription());
        }

        @Override
        public void onEvent(int i, int i1, int i2, Bundle bundle) {

        }

        @Override
        public void onVolumeChanged(int i) {

        }
    };

    public void queryResource() {
        int ret = mWakeuper.queryResource(getResource(), new RequestListener() {
            @Override
            public void onEvent(int i, Bundle bundle) {

            }

            @Override
            public void onBufferReceived(byte[] buffer) {
                try {
                    String resultInfo = new String(buffer, "utf-8");
                    LogUtils.e("resultInfo:" + resultInfo);

                    JSONTokener tokener = new JSONTokener(resultInfo);
                    JSONObject object = new JSONObject(tokener);

                    int ret = object.getInt("ret");
                    if (ret == 0) {
                        String uri = object.getString("dlurl");
                        String md5 = object.getString("md5");
                        LogUtils.e("uri:" + uri);
                        LogUtils.e("md5:" + md5);
                        LogUtils.e("请求成功");
                    }
                } catch (Exception e) {
                    e.printStackTrace();
                }
            }

            @Override
            public void onCompleted(SpeechError speechError) {
                if (speechError != null) {
                    LogUtils.e("error:" + speechError.getErrorCode());
                    LogUtils.e(speechError.getPlainDescription(true));
                }
            }
        });
    }

    private int lastVolume = 0;
    /**
     * 听写监听器。
     */
    private RecognizerListener mRecognizerListener = new RecognizerListener() {

        @Override
        public void onBeginOfSpeech() {
            // 此回调表示：sdk内部录音机已经准备好了，用户可以开始语音输入
            LogUtils.e("开始说话");

        }

        @Override
        public void onError(SpeechError error) {
            // Tips：
            // 错误码：10118(您没有说话)，可能是录音机权限被禁，需要提示用户打开应用的录音权限。
            if (mTranslateEnable && error.getErrorCode() == 14002) {
                LogUtils.e(error.getPlainDescription(true) + "\n请确认是否已开通翻译功能");
            } else {
                LogUtils.e(error.getPlainDescription(true));
                if (mSpeechDialog != null) {
                    mSpeechDialog.showError(error.getErrorDescription());
                    mSpeechDialog.getClickView().setOnClickListener(new View.OnClickListener() {
                        //重新开始监听
                        @Override
                        public void onClick(View v) {
                            mSpeechDialog.stopAndStartRender(true);
                            mRecognizer.startListening(mRecognizerListener);
                        }
                    });
                }
            }

        }

        @Override
        public void onEndOfSpeech() {
            // 此回调表示：检测到了语音的尾端点，已经进入识别过程，不再接受语音输入
            if (mSpeechDialog != null && mSpeechDialog.isShowing()) {
                mSpeechDialog.stopAndStartRender(false);
                LogUtils.v("syst=" + System.currentTimeMillis());
            }
        }

        @Override
        public void onResult(RecognizerResult results, boolean isLast) {
            if (mSpeechDialog != null) {
                mSpeechDialog.hide();
            }
            LogUtils.v("systgg=" + System.currentTimeMillis());
            printResult(results, isLast);
        }

        /**
         *
         * @param volume
         * @param data
         */
        @Override
        public void onVolumeChanged(int volume, byte[] data) {
            LogUtils.d("返回音量值：" + volume);
            if (mSpeechDialog != null) {
                mSpeechDialog.getWaveView().setRatio(Math.ceil((volume + lastVolume) / 10));
            }
            lastVolume = volume;
        }

        @Override
        public void onEvent(int eventType, int arg1, int arg2, Bundle obj) {
            // 以下代码用于获取与云端的会话id，当业务出错时将会话id提供给技术支持人员，可用于查询会话日志，定位出错原因
            // 若使用本地能力，会话id为null
            //	if (SpeechEvent.EVENT_SESSION_ID == eventType) {
            //		String sid = obj.getString(SpeechEvent.KEY_EVENT_SESSION_ID);
            //		Log.d(TAG, "session id =" + sid);
            //	}
        }
    };

    private void printResult(RecognizerResult results, boolean islast) {
        String text = JsonParser.parseIatResult(results.getResultString());

        String sn = null;
        // 读取json结果中的sn字段
        try {
            JSONObject resultJson = new JSONObject(results.getResultString());
            sn = resultJson.optString("sn");
        } catch (JSONException e) {
            e.printStackTrace();
        }

        mRecognizerResults.put(sn, text);

        StringBuffer resultBuffer = new StringBuffer();
        for (String key : mRecognizerResults.keySet()) {
            resultBuffer.append(mRecognizerResults.get(key));
        }
        recognizerResult = resultBuffer.toString();
        LogUtils.e("recognizerResult=" + recognizerResult + "/" + islast);
        if (islast) {

            String uploadUrl = "http://212.64.88.43:8080/speech/upload/uploadFile";
            HttpUtil.upLoadFile(mSamplePath + "/outfile.wav", recognizerResult, uploadUrl);

            ((IActivity) mAppManager.getTopActivity()).doSpeechEnd(recognizerResult);
        }

    }


    /**
     * 初始化监听器。
     */
    private InitListener mInitListener = new InitListener() {

        @Override
        public void onInit(int code) {
            LogUtils.v("SpeechRecognizer init() code = " + code);
            if (code != ErrorCode.SUCCESS) {
                LogUtils.e("初始化失败，错误码：" + code);
            }
        }
    };

    private String getResource() {
        final String resPath = ResourceUtil.generateResourcePath(SpeechDealService.this, ResourceUtil.RESOURCE_TYPE.assets, "ivw/" + getString(R.string.app_id) + ".jet");
        LogUtils.e("resPath: " + resPath);
        return resPath;
    }

    /**
     * 参数设置
     *
     * @return
     */
    public void setParam() {
        // 清空参数
        mRecognizer.setParameter(SpeechConstant.PARAMS, null);

        // 设置听写引擎
        mRecognizer.setParameter(SpeechConstant.ENGINE_TYPE, mEngineType);
        // 设置返回结果格式
        mRecognizer.setParameter(SpeechConstant.RESULT_TYPE, "json");

        this.mTranslateEnable = mSharedPreferences.getBoolean(this.getString(R.string.pref_key_translate), false);
        if (mTranslateEnable) {
            mRecognizer.setParameter(SpeechConstant.ASR_SCH, "1");
            mRecognizer.setParameter(SpeechConstant.ADD_CAP, "translate");
            mRecognizer.setParameter(SpeechConstant.TRS_SRC, "its");
        }

        String lag = mSharedPreferences.getString("iat_language_preference",
                "mandarin");
        if (lag.equals("en_us")) {
            // 设置语言
            mRecognizer.setParameter(SpeechConstant.LANGUAGE, "en_us");
            mRecognizer.setParameter(SpeechConstant.ACCENT, null);

            if (mTranslateEnable) {
                mRecognizer.setParameter(SpeechConstant.ORI_LANG, "en");
                mRecognizer.setParameter(SpeechConstant.TRANS_LANG, "cn");
            }
        } else {
            // 设置语言
            mRecognizer.setParameter(SpeechConstant.LANGUAGE, "zh_cn");
            // 设置语言区域
            mRecognizer.setParameter(SpeechConstant.ACCENT, lag);

            if (mTranslateEnable) {
                mRecognizer.setParameter(SpeechConstant.ORI_LANG, "cn");
                mRecognizer.setParameter(SpeechConstant.TRANS_LANG, "en");
            }
        }
        //此处用于设置dialog中不显示错误码信息
        //mRecognizer.setParameter("view_tips_plain","false");

        // 设置语音前端点:静音超时时间，即用户多长时间不说话则当做超时处理
        mRecognizer.setParameter(SpeechConstant.VAD_BOS, mSharedPreferences.getString("iat_vadbos_preference", "4000"));

        // 设置语音后端点:后端点静音检测时间，即用户停止说话多长时间内即认为不再输入， 自动停止录音
        mRecognizer.setParameter(SpeechConstant.VAD_EOS, mSharedPreferences.getString("iat_vadeos_preference", "1500"));

        // 设置标点符号,设置为"0"返回结果无标点,设置为"1"返回结果有标点
        mRecognizer.setParameter(SpeechConstant.ASR_PTT, mSharedPreferences.getString("iat_punc_preference", "0"));

        // 设置音频保存路径，保存音频格式支持pcm、wav，设置路径为sd卡请注意WRITE_EXTERNAL_STORAGE权限
        // 注：AUDIO_FORMAT参数语记需要更新版本才能生效
        mRecognizer.setParameter(SpeechConstant.AUDIO_FORMAT, "wav");
        mRecognizer.setParameter(SpeechConstant.ASR_AUDIO_PATH, mSamplePath + "/outfile.wav");
    }

    private void printTransResult(RecognizerResult results) {
        String trans = JsonParser.parseTransResult(results.getResultString(), "dst");
        String oris = JsonParser.parseTransResult(results.getResultString(), "src");

        if (TextUtils.isEmpty(trans) || TextUtils.isEmpty(oris)) {
            LogUtils.e("解析结果失败，请确认是否已开通翻译功能。");
        }

    }
}
